#include <iostream>
#include "serial/serial.h"
#include <fcntl.h>
#include <yaml-cpp/yaml.h>
#include <chrono>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <iomanip> 
#include <thread>

int main() {

    int serial_2_udp_node_port = 12344;
    std::string qgc_ip = "192.168.1.102";
    int qgc_port = 12345;
    std::string serial_name = "/dev/ttyACM0";
    int serial_baudrate = 115200;
    int serial_timeout = 10;


    try {

    // 1、使用socket()函数获取一个socket文件描述符
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (-1 == sockfd)
    {
		printf("socket open err.");
		return -1;
    }
 
    // 2、绑定本地的相关信息，如果不绑定，则系统会随机分配一个端口号
    struct sockaddr_in local_addr = {0};
    local_addr.sin_family = AF_INET;                                //使用IPv4地址
    //local_addr.sin_addr.s_addr = inet_addr("192.168.0.107");        //本机IP地址
    local_addr.sin_addr.s_addr = htonl(INADDR_ANY);
    //local_addr.sin_port = htons(12300);                             //端口
    local_addr.sin_port = htons(serial_2_udp_node_port);                             //端口
    bind(sockfd, (struct sockaddr*)&local_addr, sizeof(local_addr));//将套接字和IP、端口绑定

    fcntl(sockfd, F_SETFL, O_NONBLOCK);//非阻塞

    // 3. 准备接收方的地址和端口，'192.168.0.107'表示目的ip地址，8266表示目的端口号 
    struct sockaddr_in qgc_addr = {0};	
    qgc_addr.sin_family = AF_INET;                         // 设置地址族为IPv4
    //sock_addr.sin_port = htons(8266);						// 设置地址的端口号信息
    qgc_addr.sin_port = htons(qgc_port);
    //sock_addr.sin_addr.s_addr = inet_addr("192.168.0.107");	//　设置IP地址

    //将字符串格式的 IP 地址转换为用于网络通信的二进制格式
    if (inet_pton(AF_INET, qgc_ip.c_str(), &qgc_addr.sin_addr) <= 0) {
            std::cerr << "Invalid address\n";
            return 1;
    }



    // 创建串口对象
    serial::Serial my_serial(serial_name, serial_baudrate, serial::Timeout::simpleTimeout(serial_timeout));

    if (my_serial.isOpen()) {
        std::cout << "串口已打开" << std::endl;
    } else {
        std::cout << "串口打开失败" << std::endl;
        return 1;
    }

    std::chrono::steady_clock::time_point start_time = std::chrono::steady_clock::now();
    uint32_t serial_send_total_bytes = 0; //存放串口一分钟内发送的字节数
    uint32_t serial_recv_total_bytes = 0; //存放串口一分钟内接收的字节数
    uint32_t udp_send_total_bytes = 0; //存放udp一分钟内发送的字节数
    uint32_t udp_recv_total_bytes = 0; //存放udp一分钟内接收的字节数


    while(1)
    {
      // 获取程序开始执行的时间点
      auto start = std::chrono::high_resolution_clock::now();

      //用来存储所收到的UDP消息的发送方的地址，包括IP和端口
      struct sockaddr_in recv_addr;
      socklen_t addrlen = sizeof(recv_addr);

      uint8_t udp_recvbuf[1024] = {0};
      //udp接收
      int udp_recv_ret = recvfrom(sockfd, (char *)udp_recvbuf, 1024, MSG_DONTWAIT,(struct sockaddr*)&recv_addr,&addrlen);  //1024表示本次接收的最大字节数
      //std::cout << "接收到的字符数组是:" << std::hex << recvbuf << std::endl; //std::hex表示十六进制显示
      for (int i = 0; i < udp_recv_ret; i++) {
        //printf("%02X ", udp_recvbuf[i]);
      }

      if(udp_recv_ret > 1) 
      {
        udp_recv_total_bytes = udp_recv_total_bytes + udp_recv_ret;
        int serial_write_bytes = my_serial.write(udp_recvbuf, udp_recv_ret); //串口发送
        serial_send_total_bytes  = serial_send_total_bytes  + serial_write_bytes;
      }


      // 暂停 10 毫秒 
      std::this_thread::sleep_for(std::chrono::milliseconds(10));

      uint8_t serial_recvbuf[1024] = {0};
      // 串口接收数据
      int serial_recv_ret =  my_serial.read(serial_recvbuf, 150);  //返回缓冲区接收到的字节数目

      if(serial_recv_ret > 1)
      {
        for (int i = 0; i < serial_recv_ret; i++) {
          //printf("%02X ", serial_recvbuf[i]);
        }
        serial_recv_total_bytes = serial_recv_total_bytes + serial_recv_ret;
        //udp发送
        int udp_send_ret = sendto(sockfd, (char *)serial_recvbuf, serial_recv_ret, 0, (struct sockaddr*)&qgc_addr, sizeof(qgc_addr));

        udp_send_total_bytes = udp_send_total_bytes + udp_send_ret;
      }
      
      // 暂停 10 毫秒 
      std::this_thread::sleep_for(std::chrono::milliseconds(10));

      // 获取程序执行结束的时间点
      auto end = std::chrono::high_resolution_clock::now();
  
      // 计算程序执行时间
      std::chrono::duration<double> duration = end - start;
      double seconds = duration.count();


      // 检查是否已过去一分钟
      auto elapsed_seconds = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - start_time).count();
      if (elapsed_seconds >= 60) {
      
            // 获取当前时间
            auto now = std::chrono::system_clock::to_time_t(std::chrono::system_clock::now());
            std::cout << "Time: " << std::put_time(std::localtime(&now), "%Y-%m-%d %X") << "   \n";
            printf("=====一分钟udp接收字节数:%d\n", udp_recv_total_bytes);
            printf("=====一分钟串口发送字节数:%d\n", serial_send_total_bytes);
            printf("=====一分钟串口接收字节数:%d\n", serial_recv_total_bytes);
            printf("=====一分钟udp发送字节数:%d\n", udp_send_total_bytes);
            std::cout << "程序单次循环执行时间: " << seconds << " 秒" << std::endl;
            // 重置计数器和起始时间
            serial_send_total_bytes = 0;
            serial_recv_total_bytes = 0; 
            udp_send_total_bytes = 0; 
            udp_recv_total_bytes = 0; 
            start_time = std::chrono::steady_clock::now();
      }
      
     }

     // 关闭串口
     my_serial.close();
     std::cout << "串口已关闭" << std::endl;
    }
    catch (serial::IOException& e) {
        std::cerr << "串口通信异常：" << e.what() << std::endl;
        return 1;
    }

    return 0;
}


